package logbuffmng

import (
	"sync"
	"time"

	"starsine.cn/appTpl/cmn"
	"starsine.cn/appTpl/cmn/config/aconf"
	. "starsine.cn/appTpl/cmn/defs"
	"starsine.cn/appTpl/cmn/logs"
	"starsine.cn/appTpl/cmn/timermgr"
	"starsine.cn/appTpl/svclog/src/logproc/logbuff"
)

type LogBuffMng struct {
	size int
	data map[string]*logbuff.LogBUff

	tmID int64
	tm   *timermgr.TimerMgr

	sync.RWMutex

	appCtxt *AppContext
}

func CreateFeLogBuffMng(appCtxt *AppContext) *LogBuffMng {
	p := new(LogBuffMng)

	p.size = aconf.GetInt("SvcLog.FeLogBuff.Size", 1000, aconf.WithENV("svclog_felogbuff_size"))

	p.data = make(map[string]*logbuff.LogBUff)
	p.tmID = -1
	p.tm = cmn.GetTm()

	p.appCtxt = appCtxt

	return p
}

func (p *LogBuffMng) Start() {
	p.checkPeriod()
}

func (p *LogBuffMng) End() {
	p.tm.CancelTimer(p.tmID)
}

func (p *LogBuffMng) checkAndRecycle(params interface{}) {
	p.Recycle()
}

func (p *LogBuffMng) checkPeriod() {
	p.tmID = p.tm.AddPeriodTimer(
		time.Duration(10),
		timermgr.NewOnTimeOut(p.checkAndRecycle,
			nil,
		))
}

func (p *LogBuffMng) Get(k string) *logbuff.LogBUff {
	p.RWMutex.Lock()
	defer p.RWMutex.Unlock()

	if v, ok := p.data[k]; ok {
		return v
	}

	v := logbuff.CreateLogBUff(p.appCtxt, p.size, nil)
	p.data[k] = v

	logs.Debugf("LogBuffMng get(%s)", k)
	return v
}

func (p *LogBuffMng) Push(k string) {
	p.RWMutex.Lock()
	defer p.RWMutex.Unlock()

	if v, ok := p.data[k]; ok {
		v.Close()
		delete(p.data, k)
		logs.Debugf("LogBuffMng push(%s)", k)
	} else {
		logs.Errorf("deleting an unexist Strung(%s)", k)
	}
}

func (p *LogBuffMng) Recycle() {
	for k, v := range p.data {
		if v.IsExpired() {
			p.Push(k)
		}
	}
}
